package com.excesys.exsecs.access.controller;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.excesys.exsecs.access.constant.enums.ResponseEnum;
import com.excesys.exsecs.access.entity.AccessProduct;
import com.excesys.exsecs.access.entity.AccessSubarea;
import com.excesys.exsecs.access.vo.AccessDeviceInfoVO;
import com.excesys.exsecs.access.vo.ThingInvokeVO;
import com.excesys.exsecs.admin.api.dto.SysLogDTO;
import com.excesys.exsecs.admin.service.SysLogService;
import com.excesys.exsecs.common.core.util.R;
import com.excesys.exsecs.common.excel.annotation.RequestExcel;
import com.excesys.exsecs.common.log.annotation.SysLog;
import com.excesys.exsecs.access.entity.AccessDeviceInfo;
import com.excesys.exsecs.access.service.AccessDeviceInfoService;
import org.springframework.beans.BeanUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import com.excesys.exsecs.common.excel.annotation.ResponseExcel;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import org.springdoc.api.annotations.ParameterObject;
import org.springframework.http.HttpHeaders;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 设备信息表
 *
 * @author lxc
 * @date 2024-05-06 17:44:39
 */
@RestController
@RequiredArgsConstructor
@RequestMapping("/accessDevice" )
@Tag(description = "accessDeviceInfo" , name = "设备信息表管理" )
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
public class AccessDeviceInfoController {

    private final  AccessDeviceInfoService accessDeviceInfoService;
	private final SysLogService sysLogService;

    /**
     * 分页查询
     * @param page 分页对象
     * @param accessDeviceInfo 设备信息表
     * @return
     */
    @Operation(summary = "分页查询" , description = "分页查询" )
    @GetMapping("/page" )
    @PreAuthorize("@pms.hasPermission('access_accessDeviceInfo_view')" )
    public R getAccessDeviceInfoPage(@ParameterObject Page page, @ParameterObject AccessDeviceInfo accessDeviceInfo) {
        return R.ok(accessDeviceInfoService.queryPage(page, accessDeviceInfo));
    }

	/**
	 * 列表
	 * @param accessDeviceInfo 设备信息表
	 * @return
	 */
	@Operation(summary = "列表" , description = "列表" )
	@GetMapping("/list" )
	//@PreAuthorize("@pms.hasPermission('access_accessDeviceInfo_view')" )
	public R list(@ParameterObject AccessDeviceInfo accessDeviceInfo) {
		LambdaQueryWrapper<AccessDeviceInfo> wrapper = Wrappers.<AccessDeviceInfo>lambdaQuery()
				.like(StrUtil.isNotEmpty(accessDeviceInfo.getDeviceName()), AccessDeviceInfo::getDeviceName,
						accessDeviceInfo.getDeviceName());
		if (StrUtil.isNotBlank(accessDeviceInfo.getProductKey())){
			List<String> pkList = Arrays.stream(accessDeviceInfo.getProductKey().split(",")).collect(Collectors.toList());
			wrapper.in(AccessDeviceInfo::getProductKey, pkList);
		}
		return R.ok(accessDeviceInfoService.queryList(wrapper));
	}


    /**
     * 通过id查询设备信息表
     * @param unitNo unitNo
     * @return R
     */
    @Operation(summary = "通过id查询" , description = "通过id查询" )
    @GetMapping("/detail" )
    @PreAuthorize("@pms.hasPermission('access_accessDeviceInfo_view')" )
    public R detail(String unitNo) {
        return R.ok(accessDeviceInfoService.detail(unitNo));
    }

    /**
     * 新增设备信息表
     * @param accessDeviceInfo 设备信息表
     * @return R
     */
    @Operation(summary = "新增设备信息表" , description = "新增设备信息表" )
    @SysLog("新增设备信息表" )
    @PostMapping
    @PreAuthorize("@pms.hasPermission('access_accessDeviceInfo_add')" )
    public R save(@RequestBody AccessDeviceInfo accessDeviceInfo) {
		String unitNo = UUID.randomUUID().toString().replace("-", "");
		try {
			long count = accessDeviceInfoService.count(Wrappers.<AccessDeviceInfo>lambdaQuery().eq(AccessDeviceInfo::getDeviceName, accessDeviceInfo.getDeviceName().trim()));
			if (count > 0){
				return R.failed("设备名称已存在");
			}
			accessDeviceInfo.setUnitNo(unitNo);
			return R.ok(accessDeviceInfoService.saveDevice(accessDeviceInfo));
		} catch (Exception e){
			accessDeviceInfoService.remove(Wrappers.<AccessDeviceInfo>lambdaQuery().eq(AccessDeviceInfo::getUnitNo, unitNo));
			return R.failed("设备添加失败");
		}

    }

    /**
     * 修改设备信息表
     * @param accessDeviceInfo 设备信息表
     * @return R
     */
    @Operation(summary = "修改设备信息表" , description = "修改设备信息表" )
    @SysLog("修改设备信息表" )
    @PutMapping
    @PreAuthorize("@pms.hasPermission('access_accessDeviceInfo_edit')" )
    public R updateById(@RequestBody AccessDeviceInfo accessDeviceInfo) {
        return R.ok(accessDeviceInfoService.updateById(accessDeviceInfo));
    }

	/**
	 * 修改启用/停用按钮
	 * @param accessDeviceInfo 设备信息表
	 * @return R
	 */
	@Operation(summary = "修改启用/停用按钮" , description = "修改启用/停用按钮" )
	@PutMapping("/startStop")
	@PreAuthorize("@pms.hasPermission('access_accessDeviceInfo_edit')" )
	public R updateStartStop(@RequestBody AccessDeviceInfo accessDeviceInfo, HttpServletRequest request) {
		boolean bool = accessDeviceInfoService.updateById(accessDeviceInfo);
		SysLogDTO sysLog = new SysLogDTO();
		if (accessDeviceInfo.getUseStatus() == 0){
			sysLog.setTitle("设备停用");
		} else{
			sysLog.setTitle("设备启用");
		}
		sysLog.setLogType("0");
		sysLog.setServiceId("exsecs-boot");
		sysLog.setMethod("PUT");
		//清除设备中的物模型，
		accessDeviceInfo.setEvents(null);
		accessDeviceInfo.setProperties(null);
		accessDeviceInfo.setServices(null);
		sysLog.setParams(JSON.toJSONString(accessDeviceInfo));
		sysLog.setTenantId(1L);
		sysLog.setRequestUri(request.getRequestURI());
		sysLog.setRemoteAddr(request.getRemoteAddr());
		sysLogService.saveLog(sysLog);
		return R.ok(bool);
	}

    /**
     * 通过id删除设备信息表
     * @param ids id列表
     * @return R
     */
    @Operation(summary = "通过id删除设备信息表" , description = "通过id删除设备信息表" )
    @SysLog("通过id删除设备信息表" )
    @DeleteMapping
    @PreAuthorize("@pms.hasPermission('access_accessDeviceInfo_del')" )
    public R removeById(@RequestBody Long[] ids) {
        return R.ok(accessDeviceInfoService.removeBatch(CollUtil.toList(ids)));
    }

	/**
	 * 服务调用
	 * @return R
	 */
	@Operation(summary = "服务调用" , description = "服务调用" )
	@SysLog("服务调用" )
	@PostMapping("/service/invoke")
	@PreAuthorize("@pms.hasPermission('access_accessDeviceInfo_add')" )
	public R invoke(@Valid @RequestBody ThingInvokeVO thingInvokeVO) {
		try {
			// 如果设备离线，则直接返回离线信息
			AccessDeviceInfo device = accessDeviceInfoService.getOne(Wrappers.<AccessDeviceInfo>lambdaQuery().eq(AccessDeviceInfo::getUnitNo, thingInvokeVO.getUnitNo()));
			if (device.getOnlineStatus() == 0){
				return R.failed(ResponseEnum.OFFLINE.getName());
			}
			ThingInvokeVO invoke = accessDeviceInfoService.invoke(thingInvokeVO);
			return R.ok(invoke, ResponseEnum.SUCCESS.getName());
		} catch (Exception e) {
			return R.failed(ResponseEnum.EXCEPT.getName());
		}
	}

	/**
	 * 属性设置初始值
	 * @param accessDeviceInfo 设备信息表
	 * @return R
	 */
	@Operation(summary = "属性设置初始值" , description = "属性设置初始值" )
	@SysLog("修改设备信息表" )
	@PutMapping("/setStaticProp")
	@PreAuthorize("@pms.hasPermission('access_accessDeviceInfo_edit')" )
	public R setStaticProp(@RequestBody AccessDeviceInfo accessDeviceInfo) {
		if (ObjectUtils.isEmpty(accessDeviceInfo) || StringUtils.isBlank(accessDeviceInfo.getUnitNo())){
			R.failed("设备编码不能为空!");
		}
		return R.ok(accessDeviceInfoService.setStaticProp(accessDeviceInfo));
	}


	/**
	 * 导入用户
	 * @param excelVOList 用户列表
	 * @param bindingResult 错误信息列表
	 * @return R
	 */
	@PostMapping("/import")
	//@PreAuthorize("@pms.hasPermission('access_accessDeviceInfo_export')")
	public R importDevice(@RequestExcel List<AccessDeviceInfoVO> excelVOList, String productKey, BindingResult bindingResult) {
		if (StringUtils.isBlank(productKey)){
			return R.failed("请选择所属产品!");
		}
		if (CollectionUtils.isEmpty(excelVOList)){
			return R.failed("设备表为空!");
		}
		return accessDeviceInfoService.importDevice(excelVOList, productKey, bindingResult);
	}


    /**
     * 导出excel 表格
     * @param accessDeviceInfo 查询条件
   	 * @param ids 导出指定ID
     * @return excel 文件流
     */
    @ResponseExcel
    @GetMapping("/export")
    @PreAuthorize("@pms.hasPermission('access_accessDeviceInfo_export')" )
    public List<AccessDeviceInfoVO> export(AccessDeviceInfo accessDeviceInfo,Long[] ids) {
		return accessDeviceInfoService.exportDevice(accessDeviceInfo);
    }
}